//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-project.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

//#include "stdafx.h"
#include "wintypes.h"
#include "UploadQueue.h"
#include "packets.h"
#include "emule.h"
#include "KnownFile.h"
#include "ListenSocket.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include "ini2.h"
#define ID_UQTIMER 59742

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//TODO rewrite the whole networkcode, use overlapped sockets

static uint32 counter, sec,statsave;
static uint32 igraph, istats;

CUploadQueue::CUploadQueue(CPreferences* in_prefs){
	app_prefs = in_prefs;
	//h_timer = SetTimer(0,141,100,TimerProc);
	h_timer=new wxTimer(theApp.emuledlg,ID_UQTIMER);
	if (!h_timer)
		theApp.emuledlg->AddLogLine(false,GetResString(IDS_ERR_TIMERCREATEFAILED));
	estadatarate = 2000;
	datarate = 0;
	dataratems = 0;
	datarateave = 0;
	bannedcount = 0;
	counter=0;
	successfullupcount = 0;
	failedupcount = 0;
	totaluploadtime = 0;
	m_nUpDataRateMSOverhead = 0;
	m_nUpDatarateOverhead = 0;
	m_nUpDataOverheadSourceExchange = 0;
	m_nUpDataOverheadFileRequest = 0;
	m_nUpDataOverheadOther = 0;
	m_nUpDataOverheadServer = 0;
	m_nUpDataOverheadSourceExchangePackets = 0;
	m_nUpDataOverheadFileRequestPackets = 0;
	m_nUpDataOverheadOtherPackets = 0;
	m_nUpDataOverheadServerPackets = 0;
	m_nLastStartUpload = 0;
	m_nSumForAvgDataRate = 0;
	statsave=0;
	for (int i = 0;i != 400;i++)
		avarage_dr_list.AddHead((uint32)0);
	h_timer->Start(100);

}

void CUploadQueue::AddUpNextClient(CUpDownClient* directadd){
	POSITION toadd = 0;
	uint32	bestscore = 0;
	CUpDownClient* newclient;
	// select next client or use given client
	if (!directadd){
		POSITION pos1, pos2;
		for (pos1 = waitinglist.GetHeadPosition();( pos2 = pos1 ) != NULL;){
			waitinglist.GetNext(pos1);
			CUpDownClient* cur_client =	waitinglist.GetAt(pos2);
			// clear dead clients
			if ((::GetTickCount() - cur_client->GetLastUpRequest() > MAX_PURGEQUEUETIME) || !theApp.sharedfiles->GetFileByID(cur_client->reqfileid) ){
				RemoveFromWaitingQueue(pos2,true);	
				if (!cur_client->socket)
					cur_client->Disconnected();
			}
			// finished clearing
			else if ( (cur_client->GetScore(true) > bestscore) && (!cur_client->IsBanned()) 
				&& (!cur_client->HasLowID() || (cur_client->socket && cur_client->socket->IsConnected()) ) ){
				bestscore = cur_client->GetScore(true);
				toadd = pos2;
			}
		}
		if (!toadd)
			return;
		newclient = waitinglist.GetAt(toadd);
		RemoveFromWaitingQueue(toadd, true);
		theApp.emuledlg->transferwnd->ShowQueueCount(waitinglist.GetCount());
	}
	else
		newclient = directadd;

	if (IsDownloading(newclient)){
		return;
	}
	// tell the client that we are now ready to upload
	if (!newclient->socket || !newclient->socket->IsConnected()){
		newclient->SetUploadState(US_CONNECTING);
		newclient->TryToConnect(true);
	}
	else{
		Packet* packet = new Packet(OP_ACCEPTUPLOADREQ,0);
		theApp.uploadqueue->AddUpDataOverheadFileRequest(packet->size);
		newclient->socket->SendPacket(packet,true);
		newclient->SetUploadState(US_UPLOADING);
	}
	newclient->SetUpStartTime();
	newclient->ResetSessionUp();
	uploadinglist.AddTail(newclient);
	
	// statistic
	CKnownFile* reqfile = theApp.sharedfiles->GetFileByID((uchar*)newclient->reqfileid);
	if (reqfile)
		reqfile->statistic.AddAccepted();
	
	theApp.emuledlg->transferwnd->uploadlistctrl->AddClient(newclient);

}

void CUploadQueue::Process(){
	m_nSumForAvgDataRate -= avarage_dr_list.RemoveHead();
	avarage_dr_list.AddTail(dataratems);
	m_nSumForAvgDataRate += dataratems;
	datarate = 10 * m_nSumForAvgDataRate / avarage_dr_list.GetCount();

	dataratems = 0;
	if (AcceptNewClient() && waitinglist.GetCount()){
		m_nLastStartUpload = ::GetTickCount();
		AddUpNextClient();
	}
	if (!uploadinglist.GetCount())
		return;

	int16 clientsrdy = 0;
	for (POSITION pos = uploadinglist.GetHeadPosition();pos != 0;uploadinglist.GetNext(pos)){
		CUpDownClient* cur_client = uploadinglist.GetAt(pos);
		if ( (cur_client->socket) && (!cur_client->socket->IsBusy()) && cur_client->HasBlocks())
			clientsrdy++;
	}
	if (!clientsrdy){
		estadatarate -= 200;
		if (estadatarate < 100)
			estadatarate = 100;
		clientsrdy++;
	}
	else{
		estadatarate += 200;
		if (estadatarate > app_prefs->GetMaxUpload()*102)
			estadatarate = app_prefs->GetMaxUpload()*102;
	}
	uint32 sendperclient = estadatarate/clientsrdy;
	POSITION pos1,pos2;
	for (pos1 = uploadinglist.GetHeadPosition();( pos2 = pos1 ) != NULL; ){
		uploadinglist.GetNext(pos1);
		CUpDownClient* cur_client = uploadinglist.GetAt(pos2);
		dataratems += cur_client->SendBlockData(sendperclient);
	}
};

bool CUploadQueue::AcceptNewClient(){
	// check if we can allow a new client to start downloading form us
	if (::GetTickCount() - m_nLastStartUpload < 1000 )
		return false;
	if (uploadinglist.GetCount() < MIN_UP_CLIENTS_ALLOWED)
		return true;
	else if (uploadinglist.GetCount() >= MAX_UP_CLIENTS_ALLOWED)
		return false;
	uint32	upPerClient = UPLOAD_CLIENT_DATARATE + datarate/50;
	if( upPerClient > 10000 )
		upPerClient = 11000;
	//now the final check
	if (theApp.glob_prefs->GetMaxUpload() == UNLIMITED){
		if ((uint32)uploadinglist.GetCount() < ((datarate/upPerClient)+2))
			return true;
	}
	else{
		uint16 nMaxSlots = 0;
		if (theApp.glob_prefs->GetMaxUpload() > 10){
			nMaxSlots += 2;
			nMaxSlots += (uint16)ceil((float)((theApp.glob_prefs->GetMaxUpload() - 10)*1024) / upPerClient);
		}
		else
			nMaxSlots = MIN_UP_CLIENTS_ALLOWED;
		if ((uint32)uploadinglist.GetCount() < (datarate/UPLOAD_CHECK_CLIENT_DR) && uploadinglist.GetCount() <= nMaxSlots )
			return true;
		
	}
	//nope
	return false;
}



#if 0
void CUploadQueue::AddUpNextClient(CUpDownClient* directadd){
	POSITION toadd = 0;
	uint32	bestscore = 0;
	CUpDownClient* newclient;
	// select next client or use given client
	if (!directadd){
		POSITION pos1, pos2;
		for (pos1 = waitinglist.GetHeadPosition();( pos2 = pos1 ) != NULL;){
			waitinglist.GetNext(pos1);
			CUpDownClient* cur_client =	waitinglist.GetAt(pos2);
			// clear dead clients
			if (::GetTickCount() - cur_client->GetLastUpRequest() > MAX_PURGEQUEUETIME){
				RemoveFromWaitingQueue(pos2,true);	
				if (!cur_client->socket)
					cur_client->Disconnected();
			}
			// finished clearing
			else if ( (cur_client->GetScore(true) > bestscore) && (!cur_client->IsBanned()) 
				&& (!cur_client->HasLowID() || (cur_client->socket && cur_client->socket->IsConnected()) ) ){
				bestscore = cur_client->GetScore(true);
				toadd = pos2;
			}
		}
		if (!toadd)
			return;
		newclient = waitinglist.GetAt(toadd);
		RemoveFromWaitingQueue(toadd, true);
		theApp.emuledlg->transferwnd->ShowQueueCount(waitinglist.GetCount());
	}
	else
		newclient = directadd;

	if (IsDownloading(newclient)){
		return;
	}
	// tell the client that we are now ready to upload
	if (!newclient->socket || !newclient->socket->IsConnected()){
		newclient->SetUploadState(US_CONNECTING);
		newclient->TryToConnect(true);
	}
	else{
		Packet* packet = new Packet(OP_ACCEPTUPLOADREQ,0);
		newclient->socket->SendPacket(packet,true);
		newclient->SetUploadState(US_UPLOADING);
	}
	newclient->SetUpStartTime();
	uploadinglist.AddTail(newclient);
	
	// statistic
	CKnownFile* reqfile = theApp.sharedfiles->GetFileByID((uchar*)newclient->reqfileid);
	if (reqfile)
		reqfile->statistic.AddAccepted();
	
	theApp.emuledlg->transferwnd->uploadlistctrl->AddClient(newclient);

}

void CUploadQueue::Process(){
	avarage_dr_list.RemoveHead();
	avarage_dr_list.AddTail(dataratems);
	datarate = 0;
	for (POSITION pos = avarage_dr_list.GetHeadPosition();pos != 0;avarage_dr_list.GetNext(pos))
		datarate += avarage_dr_list.GetAt(pos);
	datarate /= (avarage_dr_list.GetCount()/10);

	dataratems = 0;
	if (AcceptNewClient() && waitinglist.GetCount())
		AddUpNextClient();
	if (!uploadinglist.GetCount())
		return;

	int16 clientsrdy = 0;
	for (POSITION pos = uploadinglist.GetHeadPosition();pos != 0;uploadinglist.GetNext(pos)){
		CUpDownClient* cur_client = uploadinglist.GetAt(pos);
		if ( (cur_client->socket) && (!cur_client->socket->IsBusy()) && cur_client->HasBlocks())
			clientsrdy++;
	}
	if (!clientsrdy){
		estadatarate -= 200;
		if (estadatarate < 100)
			estadatarate = 100;
		clientsrdy++;
	}
	else{
		estadatarate += 200;
		if (estadatarate > app_prefs->GetMaxUpload()*102)
			estadatarate = app_prefs->GetMaxUpload()*102;
	}
	uint32 sendperclient = estadatarate/clientsrdy;
	POSITION pos1,pos2;
	for (pos1 = uploadinglist.GetHeadPosition();( pos2 = pos1 ) != NULL; ){
		uploadinglist.GetNext(pos1);
		CUpDownClient* cur_client = uploadinglist.GetAt(pos2);
		dataratems += cur_client->SendBlockData(sendperclient);
	}
};

bool CUploadQueue::AcceptNewClient(){
	// check if we can allow a new client to start downloading form us
	if (uploadinglist.GetCount() < MIN_UP_CLIENTS_ALLOWED)
		return true;
	else if (uploadinglist.GetCount() >= MAX_UP_CLIENTS_ALLOWED)
		return false;

	//now the final check
	if (theApp.glob_prefs->GetMaxUpload() == UNLIMITED){
		if ((uint32)uploadinglist.GetCount() < (datarate/UPLOAD_CLIENT_DATARATE))
			return true;
	}
	else{
		uint16 nMaxSlots = 0;
		if (theApp.glob_prefs->GetMaxUpload() > 10){
			nMaxSlots += 4;
			nMaxSlots += (uint16)ceil((((theApp.glob_prefs->GetMaxUpload() - 10)*1024) / UPLOAD_CLIENT_DATARATE)) ;
		}
		else
			nMaxSlots = MIN_UP_CLIENTS_ALLOWED;
		if ((uint32)uploadinglist.GetCount() < (datarate/UPLOAD_CHECK_CLIENT_DR) && uploadinglist.GetCount() <= nMaxSlots )
			return true;
		
	}
	//nope
	return false;
}
#endif

CUploadQueue::~CUploadQueue(){
  //KillTimer(0,141);
  delete h_timer;
}

POSITION CUploadQueue::GetWaitingClient(CUpDownClient* client){
	return waitinglist.Find(client); 
}

/*
POSITION CUploadQueue::GetWaitingClientByID(CUpDownClient* client){
	for (POSITION pos = waitinglist.GetHeadPosition();pos != 0;waitinglist.GetNext(pos)){
		if (client->Compare(waitinglist.GetAt(pos)))
			return pos;
	}
	return 0;
}
*/

CUpDownClient* CUploadQueue::GetWaitingClientByIP(uint32 dwIP){
	for (POSITION pos = waitinglist.GetHeadPosition();pos != 0;waitinglist.GetNext(pos)){
		if (dwIP == waitinglist.GetAt(pos)->GetIP())
			return waitinglist.GetAt(pos);
	}
	return 0;
}

POSITION CUploadQueue::GetDownloadingClient(CUpDownClient* client){
	for (POSITION pos = uploadinglist.GetHeadPosition();pos != 0;uploadinglist.GetNext(pos)){
		if (client == uploadinglist.GetAt(pos))
			return pos;
	}
	return 0;
}

void CUploadQueue::UpdateBanCount(){
	int count=0;
	for (POSITION pos = waitinglist.GetHeadPosition();pos != 0;waitinglist.GetNext(pos)){
		CUpDownClient* cur_client= waitinglist.GetAt(pos);
		if(cur_client->IsBanned())
			count++;
	}
	SetBanCount(count);
}
void CUploadQueue::AddClientToQueue(CUpDownClient* client, bool bIgnoreTimelimit){
	if (theApp.serverconnect->IsConnected() && theApp.serverconnect->IsLowID()
		&& !theApp.serverconnect->IsLocalServer(client->GetServerIP(),client->GetServerPort())
		&& client->GetDownloadState() == DS_NONE && !client->IsFriend()
		&& GetWaitingUserCount() > 50)
		return;
	client->AddAskedCount();
	client->SetLastUpRequest();
	if (!bIgnoreTimelimit){
		if (client->IsBanned()){
			if (::GetTickCount() - client->GetBanTime() > 18000000){
				client->UnBan();
			}
			else
				return;
		}
		client->AddRequestCount(client->reqfileid);
	}
	// check for double
	for (POSITION pos = waitinglist.GetHeadPosition();pos != 0;waitinglist.GetNext(pos)){
		CUpDownClient* cur_client= waitinglist.GetAt(pos);
		if (cur_client == client){	//already on queue
			client->SendRankingInfo();
			theApp.emuledlg->transferwnd->queuelistctrl->RefreshClient(client);
			return;			
		}
		else if ( client->Compare(cur_client) ) {
			// another client with same ip or hash
			theApp.emuledlg->AddDebugLogLine(false,CString(GetResString(IDS_SAMEUSERHASH)),client->GetUserName(),cur_client->GetUserName(),cur_client->GetUserName() );
			RemoveFromWaitingQueue(pos,true);	
			if (!cur_client->socket)
				cur_client->Disconnected();	
			return;
		}
	}
	// done

	// Add clients server to list.
	if (theApp.glob_prefs->AddServersFromClient()){
		in_addr host;
		host.s_addr = client->GetServerIP();
		CServer* srv = new CServer(client->GetServerPort(), inet_ntoa(host));
		srv->SetListName(srv->GetAddress());

		if (!theApp.emuledlg->serverwnd->serverlistctrl->AddServer(srv, true))
			delete srv;
		/*else
			theApp.emuledlg->AddLogLine(false,"Added new server: %s:%d", srv->GetFullIP(), srv->GetPort());*/
	}

	// statistic values
	CKnownFile* reqfile = theApp.sharedfiles->GetFileByID((uchar*)client->reqfileid);
		if (reqfile)
			reqfile->statistic.AddRequest();
	// TODO find better ways to cap the list
		if ((uint32)waitinglist.GetCount() > (theApp.glob_prefs->GetQueueSize()+bannedcount))
		return;
	if (client->IsDownloading()){
		// he's already downloading and wants probably only another file
		Packet* packet = new Packet(OP_ACCEPTUPLOADREQ,0);
		theApp.uploadqueue->AddUpDataOverheadFileRequest(packet->size);
		client->socket->SendPacket(packet,true);
		return;
	}
	if (waitinglist.IsEmpty() && AcceptNewClient()){
		AddUpNextClient(client);
		m_nLastStartUpload = ::GetTickCount();
	}
	else{
		waitinglist.AddTail(client);
		client->SetUploadState(US_ONUPLOADQUEUE);
		client->SendRankingInfo();
		theApp.emuledlg->transferwnd->queuelistctrl->AddClient(client);
		theApp.emuledlg->transferwnd->ShowQueueCount(waitinglist.GetCount());
	}
}

bool CUploadQueue::RemoveFromUploadQueue(CUpDownClient* client, bool updatewindow){
	for (POSITION pos = uploadinglist.GetHeadPosition();pos != 0;uploadinglist.GetNext(pos)){
		if (client == uploadinglist.GetAt(pos)){
			if (updatewindow)
				theApp.emuledlg->transferwnd->uploadlistctrl->RemoveClient(uploadinglist.GetAt(pos));
			uploadinglist.RemoveAt(pos);
			if( client->GetTransferedUp() ){
				successfullupcount++;
				totaluploadtime += client->GetUpStartTimeDelay()/1000;
			}
			else
				failedupcount++;
			client->SetUploadState(US_NONE);
			client->ClearUploadBlockRequests();
			return true;
		}
	}
	return false;
}

uint32 CUploadQueue::GetAverageUpTime(){
	if( successfullupcount ){
		return totaluploadtime/successfullupcount;
	}
	return 0;
}

bool CUploadQueue::RemoveFromWaitingQueue(CUpDownClient* client, bool updatewindow){
	POSITION pos = waitinglist.Find(client);
	if (pos){
		RemoveFromWaitingQueue(pos,updatewindow);
		if (updatewindow)
			theApp.emuledlg->transferwnd->ShowQueueCount(waitinglist.GetCount());
		return true;
	}
	else
		return false;
}

void CUploadQueue::RemoveFromWaitingQueue(POSITION pos, bool updatewindow){	
	CUpDownClient* todelete = waitinglist.GetAt(pos);
	waitinglist.RemoveAt(pos);
	if( todelete->IsBanned() )
		todelete->UnBan();
	//if (updatewindow)
	theApp.emuledlg->transferwnd->queuelistctrl->RemoveClient(todelete);
	todelete->SetUploadState(US_NONE);
}

bool CUploadQueue::CheckForTimeOver(CUpDownClient* client){
	if (theApp.glob_prefs->TransferFullChunks())
	{
		if( client->GetUpStartTimeDelay() > 3600000 ) // Try to keep the clients from downloading for ever.
			return true;
// For some reason, some clients can continue to download after a chunk size.
// Are they redownloading the same chunk over and over????
		if( client->GetSessionUp() > 10485760 ) 
			return true;
	}
	else
	{
		for (POSITION pos = waitinglist.GetHeadPosition();pos != 0;waitinglist.GetNext(pos)){
			if (client->GetScore(true,true) < waitinglist.GetAt(pos)->GetScore(true,false))
				return true;
		}
	}
	return false;
}

void CUploadQueue::DeleteAll(){
	waitinglist.RemoveAll();
	uploadinglist.RemoveAll();
}

uint16 CUploadQueue::GetWaitingPosition(CUpDownClient* client){
	if (!IsOnUploadQueue(client))
		return 0;
	uint16 rank = 1;
	uint32 myscore = client->GetScore(false);
	for (POSITION pos = waitinglist.GetHeadPosition();pos != 0;waitinglist.GetNext(pos)){
		if (waitinglist.GetAt(pos)->GetScore(false) > myscore)
			rank++;
	}
	return rank;
}

void CUploadQueue::CompUpDatarateOverhead(){
	this->m_AvarageUDRO_list.AddTail(m_nUpDataRateMSOverhead);
	if (m_AvarageUDRO_list.GetCount() > 150)
		m_AvarageUDRO_list.RemoveAt(m_AvarageUDRO_list.GetHeadPosition());
	m_nUpDatarateOverhead = 0;
	m_nUpDataRateMSOverhead = 0;
	for (POSITION pos = m_AvarageUDRO_list.GetHeadPosition();pos != 0;m_AvarageUDRO_list.GetNext(pos))
		m_nUpDatarateOverhead += m_AvarageUDRO_list.GetAt(pos);

	if(m_AvarageUDRO_list.GetCount() > 10)
		m_nUpDatarateOverhead = 10*m_nUpDatarateOverhead/m_AvarageUDRO_list.GetCount();
	else
		m_nUpDatarateOverhead = 0;
	return;
}

void TimerProc() {
  // can this actually happen under wxwin?
	if (!theApp.emuledlg->IsRunning())
		return;

	theApp.uploadqueue->Process();
	theApp.downloadqueue->Process();
	//theApp.clientcredits->Process();
	theApp.uploadqueue->CompUpDatarateOverhead();
	theApp.downloadqueue->CompDownDatarateOverhead();
	counter++;

	// one second
	if (counter >= 10){
		counter=0;

		theApp.clientcredits->Process();
		theApp.serverlist->Process();
		theApp.friendlist->Process();
		if( theApp.serverconnect->IsConnecting() && !theApp.serverconnect->IsSingleConnect() )
			theApp.serverconnect->TryAnotherConnectionrequest();
		theApp.emuledlg->statisticswnd->UpdateConnectionsStatus();
		if (theApp.serverconnect->IsConnecting()) theApp.serverconnect->CheckForTimeout();

		// display graphs
		if (theApp.glob_prefs->GetTrafficOMeterInterval()>0) {
			igraph++;

			if (igraph >= (uint32)(theApp.glob_prefs->GetTrafficOMeterInterval()) ) {
				igraph=0;
				theApp.emuledlg->statisticswnd->SetCurrentRate((float)theApp.uploadqueue->GetDatarate()/1024,(float)theApp.downloadqueue->GetDatarate()/1024);
			}
		}
		if (theApp.emuledlg->activewnd == theApp.emuledlg->statisticswnd) {    
			// display stats
			if (theApp.glob_prefs->GetStatsInterval()>0) {
				istats++;

				if (istats >= (uint32)(theApp.glob_prefs->GetStatsInterval()) ) {
					istats=0;
					theApp.emuledlg->ShowStatistics();
				}
			}
	}
		//save rates every second
		theApp.emuledlg->statisticswnd->RecordRate();

		
		sec++;
		// 5 seconds
		if (sec>=5) {

			#ifdef _DEBUG
				if (!AfxCheckMemory()) AfxDebugBreak();
			#endif

			sec = 0;
			theApp.listensocket->Process();
			theApp.OnlineSig(); // Added By Bouc7 
			theApp.emuledlg->ShowTransferRate();

		}

		statsave++;
		if (statsave>=60) {
			statsave=0;
			CString buffer;
			char* fullpath = new char[strlen(theApp.glob_prefs->GetAppDir())+16];
			sprintf(fullpath,"%spreferences.ini",theApp.glob_prefs->GetAppDir());
			CIni ini( fullpath, "eMule" );
			delete[] fullpath;

			buffer.Format("%I64Lu",theApp.stat_sessionReceivedBytes+theApp.glob_prefs->GetTotalDownloaded());
			ini.WriteString("TotalDownloadedBytes",buffer ,"Statistics");

			buffer.Format("%I64Lu",theApp.stat_sessionSentBytes+theApp.glob_prefs->GetTotalUploaded());
			ini.WriteString("TotalUploadedBytes",buffer ,"Statistics");
		}
	}

}

CUpDownClient* CUploadQueue::GetNextClient(CUpDownClient* lastclient){
	if (waitinglist.IsEmpty())
		return 0;
	if (!lastclient)
		return waitinglist.GetHead();
	POSITION pos = waitinglist.Find(lastclient);
	if (!pos){
		return waitinglist.GetHead();
	}
	waitinglist.GetNext(pos);
	if (!pos)
		return NULL;
	else
		return waitinglist.GetAt(pos);
}

void CUploadQueue::FindSourcesForFileById(CTypedPtrList<CPtrList, CUpDownClient*>* srclist, uchar* filehash) {
	POSITION pos;
	
	pos = uploadinglist.GetHeadPosition();
	while(pos) {
		CUpDownClient *potential = uploadinglist.GetNext(pos);
		if(memcmp(potential->reqfileid, filehash, 16) == 0)
			srclist->AddTail(potential);
	}

	pos = waitinglist.GetHeadPosition();
	while(pos) {
		CUpDownClient *potential = waitinglist.GetNext(pos);
		if(memcmp(potential->reqfileid, filehash, 16) == 0)
			srclist->AddTail(potential);
	}
}
